package edu.cmu.abi.track;

import edu.cmu.abi.*;
import java.sql.SQLException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import edu.cmu.abi.track.Characteristic;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.lang.ArrayUtils;

import Jama.Matrix;
import ncsa.hdf.object.h5.H5File;
import static java.lang.System.out;
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author SimplyYogi
 */
public class Track {

    public enum CharacteristicType {

        PITCH, TIMBRE, ALL
    }
    private static DecimalFormat df = new DecimalFormat("##.##");
    private String trackID = "";

    public String getTrackID() {
        return trackID;
    }

    public void setTrackID(String trackID) {
        this.trackID = trackID;
    }
    private String path = "";
    private Characteristic timbre = null;
    private Characteristic pitch = null;
    private H5File trackFile = null;
    private double[] segments_start;
    private String title;
    private String basePath = "F:/MillionSong/Extracted/"; //default path for track location

    public Track(String trackID) {
        this.trackID = trackID;
        String location = trackID.charAt(2) + "/" + trackID.charAt(3) + "/" + trackID.charAt(4) + "/";
        this.path = basePath + location;
    }

    public Track(String path, String trackID) {
        this.trackID = trackID;
        this.basePath = path;
        String location = trackID.charAt(2) + "/" + trackID.charAt(3) + "/" + trackID.charAt(4) + "/";
        this.path = basePath + location;
    }

    public Characteristic getTimbre() {
        return timbre;
    }

    public void setTimbre(Characteristic timbre) {
        this.timbre = timbre;
    }

    public Characteristic getPitch() {
        return pitch;
    }

    public void setPitch(Characteristic pitch) {
        this.pitch = pitch;
    }

    public double[] getSegments_start() {
        return segments_start;
    }

    public void setSegments_start(double[] segments_start) {
        this.segments_start = segments_start;
    }

    public void loadCharacteristics() throws Exception {
        if (this.path == "") {
            throw new Exception("You must specify the correct path. track.setPath()");
        }
        H5File h5 = hdf5_getters.hdf5_open_readonly(this.path + "/" + this.trackID + ".h5");
        try {
            double starts[] = hdf5_getters.get_segments_start(h5);
            this.setSegments_start(starts);

            double pitch[] = hdf5_getters.get_segments_pitches(h5);
            this.pitch = new Characteristic(pitch, 12, 0.1, this.segments_start);

            double timbre[] = hdf5_getters.get_segments_timbre(h5);
            this.timbre = new Characteristic(timbre, 12, 0.1, this.segments_start);

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        hdf5_getters.hdf5_close(h5);
    }

    public static Matrix getCharacteristicMatrix(Characteristic[] A, Characteristic[] B) {
        if (A.length != B.length) {
            return null;
        }

        for (int i = 0; i < A.length; i++) {
            if (A[i].getNumOfSegment() != B[i].getNumOfSegment()) {
                return null;
            }
        }
        ArrayList<Double> meanA = new ArrayList<Double>();
        for (Characteristic a : A) {
            meanA.addAll(Arrays.asList(ArrayUtils.toObject(a.getSegmentsMean())));
        }

        ArrayList<Double> varA = new ArrayList<Double>();
        for (Characteristic a : A) {
            varA.addAll(Arrays.asList(ArrayUtils.toObject(a.getSegmentsVariance())));
        }

        ArrayList<Double> meanB = new ArrayList<Double>();
        for (Characteristic b : B) {
            meanB.addAll(Arrays.asList(ArrayUtils.toObject(b.getSegmentsMean())));
        }

        ArrayList<Double> varB = new ArrayList<Double>();
        for (Characteristic b : B) {
            varB.addAll(Arrays.asList(ArrayUtils.toObject(b.getSegmentsVariance())));
        }

        double[] meansA = ArrayUtils.toPrimitive(meanA.toArray(new Double[0]));
        double[] varsA = ArrayUtils.toPrimitive(varA.toArray(new Double[0]));

        double[] meansB = ArrayUtils.toPrimitive(meanB.toArray(new Double[0]));
        double[] varsB = ArrayUtils.toPrimitive(varB.toArray(new Double[0]));
        Matrix temp = new Matrix(2, 240);

        for (int i = 0; i < 120; i++) {
            temp.set(0, i, meansA[i]);
        }
        for (int i = 120; i < 240; i++) {
            temp.set(0, i, varsA[i - 120]);
        }

        for (int i = 0; i < 120; i++) {
            temp.set(1, i, meansB[i]);
        }
        for (int i = 120; i < 240; i++) {
            temp.set(1, i, varsB[i - 120]);
        }
        return temp;
    }

    public static Matrix getCharacteristicMatrix(Characteristic characterA,
            Characteristic characterB) {
        if (characterA.getNumOfSegment() != characterB.getNumOfSegment()) {
            return null;
        }

        double[] meansA = characterA.getSegmentsMean();
        double[] varA = characterA.getSegmentsVariance();

        double[] meansB = characterB.getSegmentsMean();
        double[] varB = characterB.getSegmentsVariance();

        Matrix temp = new Matrix(2, 240);

        for (int i = 0; i < 120; i++) {
            temp.set(0, i, meansA[i]);
        }
        for (int i = 120; i < 240; i++) {
            temp.set(0, i, varA[i - 120]);
        }

        for (int i = 0; i < 120; i++) {
            temp.set(1, i, meansB[i]);
        }
        for (int i = 120; i < 240; i++) {
            temp.set(1, i, varB[i - 120]);
        }
        return temp;
    }

    public Matrix getTrackMatrix(Track otherTrack, CharacteristicType type) {
        Matrix matrix;
        switch (type) {
            case TIMBRE: {
                Characteristic[] cA = {this.getPitch(), this.getTimbre()};
                Characteristic[] cB = {otherTrack.getPitch(), otherTrack.getTimbre()};
                matrix = Track.getCharacteristicMatrix(cA, cB);
                break;
            }
            case PITCH: {
                matrix = Track.getCharacteristicMatrix(this.getPitch(), otherTrack.getPitch());
                break;
            }
            case ALL: {
                matrix = Track.getCharacteristicMatrix(this.getPitch(), otherTrack.getPitch());
                break;
            }
            default: {
                matrix = null;
                break;
            }
        }
        return matrix;
    }

    public static void printMatrix(String path, String file, Matrix m) {
        StringBuffer sb=new StringBuffer();
        int rows = m.getRowDimension();
        int columns = m.getColumnDimension();
        int count = 0;
        System.out.println("------Printing Matrix");
        for (int row = 0; row < rows; row++) {
            for (int column = 0; column < columns; column++) {
                System.out.print(df.format(m.get(row, column)) + "\t");
                sb.append(df.format(m.get(row, column)) + "\t");
                count++;
            }
            
            count = 0;
        }
        System.out.print("\n");
        sb.append("\n");

        Util.writeToFile(path, file, sb, true);
    }

    public String toString() {
        StringBuffer sb = new StringBuffer();
        sb.append("TIMBRE------------------------------\n");
        sb.append(timbre.toString());
        sb.append("PITCH------------------------------\n");
        sb.append(pitch.toString());
        return sb.toString();

    }

    public void setTitle(String title) {
        this.title = title;

    }
    public static void printCharacteristics(Connection con) throws SQLException {

        PreparedStatement statement = null;
        ArrayList<Track> trackList = new ArrayList<Track>();

        try {

            statement = con.prepareStatement("select track_id, title, ID "
                    + "from cover_song");

            ResultSet result = statement.executeQuery();
            int counter=0;
            while (result.next()) {
                StringBuffer sb=new StringBuffer();
                sb.append(result.getString(1)+"\n");
                System.out.println(result.getString(1)+result.getString(2)+result.getString(3));
                
                Track track = new Track(result.getString(1));
                track.setTitle(result.getString(2));
                track.loadCharacteristics();

                Matrix mAttr = track.getCharacteristicMatrix(track.getTimbre(), track.getPitch());
                
                /*
                 * Write track_id to track.txt and write track's timbre and pitches to a separate file
                 */
                Util.writeToFile("C:\\Users\\SimplyYogi\\Documents\\NetBeansProjects\\MSD\\trunk\\", "track.txt", sb, true);
                track.printMatrix("C:\\Users\\SimplyYogi\\Documents\\NetBeansProjects\\MSD\\trunk\\", "characteristics.txt", mAttr);

                track.finalize();
                //trackList.add(track);
                
            } 

        } catch (Throwable ex) {
            Logger.getLogger(Track.class.getName()).log(Level.SEVERE, null, ex);
       
        } finally {

            if (statement != null) {
                statement.close();

            }
        }

       

    }

}
